/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2010 huliqing, huliqing.cn@gmail.com
 *
 * This file is part of QFaces.
 * QFaces is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * QFaces is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with QFaces.  If not, see <http://www.gnu.org/licenses/>.
 *
 * 这个文件是QFaces的一部分。
 * 您可以单独使用或分发这个文件，但请不要移除这个头部声明信息.
 * QFaces是一个自由软件，您可以自由分发、修改其中的源代码或者重新发布它，
 * 新的任何修改后的重新发布版必须同样在遵守LGPL3或更后续的版本协议下发布.
 * 关于LGPL协议的细则请参考COPYING、COPYING.LESSER文件，
 * 您可以在QFaces的相关目录中获得LGPL协议的副本，
 * 如果没有找到，请连接到 http://www.gnu.org/licenses/ 查看并获取副本。
 *
 * - Author: Huliqing
 * - Contact: huliqing.cn@gmail.com
 * - License: GNU Lesser General Public License (LGPL)
 * - Blog and source code availability: http://www.huliqing.name/
 */


package name.huliqing.qfaces.component;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.el.MethodExpression;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.xml.parsers.ParserConfigurationException;
import name.huliqing.qfaces.QFaces;
import name.huliqing.qfaces.XmlOper;
import name.huliqing.qfaces.model.Node;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * 
 * @author huliqing
 */
public class Tree extends UIComponentBase implements Ajax {
	private final static Logger logger = Logger.getLogger(Tree.class.getName());

	// ---- 参数
	private MethodExpression listener;	// 节点侦听器
	private Boolean showRoot; 			// 是否显示根节点
	private String rootName;			// 根节点名称
	private String srcImageDefault;		// 默认的节点标识图标(路径)
	private Boolean autoInitRoot;		// 首次载入时，自动装载root的子节点
	
	// ---- 内部参数
	private String ID_CLIENT;			// 组件ID，包含整颗树
	
	private String srcClosedLast;
	private String srcClosedMiddle;
	private String srcOpenedLast;
	private String srcOpenedMiddle;
	private String srcLeafLast;
	private String srcLeafMiddle;
	private String srcLink;
	
	public void setListener(MethodExpression listener) {
        this.listener = listener;
    }
	
	@Override
	public Object saveState(FacesContext fc) {
		Object[] obj = new Object[2];
		obj[0] = super.saveState(fc);
		obj[1] = this.listener;
		return obj;
	}
  
	@Override
	public void restoreState(FacesContext fc, Object state) {
	    Object[] obj = (Object[]) state;
	    super.restoreState(fc, obj[0]);
	    this.listener = (MethodExpression) obj[1];
	}
	
    @Override
    public void encodeBegin(FacesContext fc) throws IOException {
    	// 载入资源文件
    	QFaces.getResLoader2().loadJavaScript(this, "Tree.js");

    	// 参数
    	showRoot = QFaces.convertToBoolean(QFaces.getAttribute(this, "showRoot", true));
    	rootName = (String) QFaces.getAttribute(this, "rootName", "Root");
    	srcImageDefault = (String) QFaces.getAttribute(this, "srcImageDefault", "");
    	autoInitRoot = QFaces.convertToBoolean(QFaces.getAttribute(this, "autoInitRoot", true));
    	
    	// 获取参数及内部参数值
    	this.ID_CLIENT = this.getClientId(fc);
    	
    	// 图片文件
    	srcClosedLast = QFaces.getResLoader2().makeImageSrc("11-closed-last.gif");
    	srcClosedMiddle = QFaces.getResLoader2().makeImageSrc("11-closed-middle.gif");
    	srcOpenedLast = QFaces.getResLoader2().makeImageSrc("11-opened-last.gif");
    	srcOpenedMiddle = QFaces.getResLoader2().makeImageSrc("11-opened-middle.gif");
    	srcLeafLast = QFaces.getResLoader2().makeImageSrc("11-leaf-last.gif");
    	srcLeafMiddle = QFaces.getResLoader2().makeImageSrc("11-leaf-middle.gif");
    	srcLink = QFaces.getResLoader2().makeImageSrc("11-link.gif");
    	
    	// 渲染组件
    	ResponseWriter rw = fc.getResponseWriter();
    	rw.startElement("span", this);
    	rw.writeAttribute("id", this.ID_CLIENT, null);
    	rw.writeAttribute("name", this.ID_CLIENT, null);
    	rw.writeAttribute("style", "border:0;", null);
    	rw.endElement("span");
    	
    	// Init
        StringBuilder jsInit = new StringBuilder("Q.F.UITree.init(")
                .append(" '" + this.ID_CLIENT 				+ "'")
                .append(",'" + this.getClass().getName() 	+ "'")
                .append(",'" + this.listener.getExpressionString() 	+ "'")
                .append(",'" + this.srcClosedLast 	+ "'")
                .append(",'" + this.srcClosedMiddle + "'")
                .append(",'" + this.srcOpenedLast 	+ "'")
                .append(",'" + this.srcOpenedMiddle + "'")
                .append(",'" + this.srcLeafLast 	+ "'")
                .append(",'" + this.srcLeafMiddle 	+ "'")
                .append(",'" + this.srcLink 		+ "'")
                .append(",'" + this.showRoot 		+ "'")
                .append(",'" + this.rootName 		+ "'")
                .append(",'" + this.srcImageDefault + "'")
                .append(",'" + this.autoInitRoot 	+ "'")
                .append(")");
        QFaces.getResLoader2().loadJavaScriptInit(this, jsInit.toString());
    	
    }
    
    // ---------- ajax 
    
    public void ajax(Map<String, String> params, FacesContext fc) {
    	String listenerExp = params.get("listenerExp");
    	Node currentNode = this.restoreNodeState(params); // 恢复Node的关系。
    	MethodExpression me = QFaces.createMethodExpression(listenerExp, 
        		List.class, new Class[]{Node.class});
        List<Node> results = (List<Node>) me.invoke(fc.getELContext(), new Object[]{currentNode});
        response(fc, results == null ? null : results);
    }
    
    public void response(FacesContext fc, List<Node> results) {
        if (results == null || results.isEmpty()) {
            QFaces.getResponse().responseHTML(fc, "");
            return;
        }
        try {
            Document doc = XmlOper.newDocument();
            Element nodes = doc.createElement("nodes");
            doc.appendChild(nodes);
            for (Node n : results) {
                Element node = doc.createElement("node");
                node.setAttribute("id", n.getId());
                node.setAttribute("value", n.getValue());
                node.setAttribute("leaf", String.valueOf(n.isLeaf()));
                node.setAttribute("icon", n.getIcon());
                node.setAttribute("url", n.getUrl());
                node.setAttribute("urlTarget", n.getUrlTarget());
                nodes.appendChild(node);
            }
            QFaces.getResponse().responseXML(fc, doc);
        } catch (ParserConfigurationException e) {
        	logger.severe(e.getMessage());
        }
    }
    
    private Node restoreNodeState(Map<String, String> params) {
        // 获取所有节点信息的总数。
        int levelCount = 0;
        levelCount = Integer.valueOf(params.get("levelCount"));
        Node parentNode = null;
        Node currentNode = null;
        for (int i = 0; i < levelCount; i++) {
            String id = params.get("id" + i);
            String value = params.get("value" + i);
            String leaf = params.get("leaf" + i);
            String icon = params.get("icon" + i);
            String url = params.get("url" + i);
            String urlTarget = params.get("urlTarget" + i);
            
            currentNode = new Node();
            currentNode.setId(id);
            currentNode.setValue(value);
            currentNode.setLeaf(Boolean.valueOf(leaf));
            currentNode.setIcon(icon);
            currentNode.setUrl(url);
            currentNode.setUrlTarget(urlTarget);
            currentNode.setParent(parentNode); // 设置父节点
            parentNode = currentNode;
        }
        return currentNode;
    }

	@Override
	public String getFamily() {
		return getClass().getName();
	}
    
}
